package cn.com.cifi.mars.service.impl;

import cn.com.cifi.mars.bean.bo.approval.ApprovalSubmitBO;
import cn.com.cifi.mars.common.exception.MsgException;
import cn.com.cifi.mars.constant.*;
import cn.com.cifi.mars.entity.ApprovalBill;
import cn.com.cifi.mars.entity.ApprovalBillDetail;
import cn.com.cifi.mars.mapper.mars.ApprovalBillDetailMapper;
import cn.com.cifi.mars.mapper.mars.ApprovalBillMapper;
import cn.com.cifi.mars.mapper.mars.ApprovedProjectMapper;
import cn.com.cifi.mars.service.SubmitApprovedProjectService;
import cn.com.cifi.mars.util.SysLogUtils;
import cn.com.cifi.mars.util.UUIDUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import cn.com.cifi.mars.service.ApprovalBillService;
import cn.com.cifi.mars.util.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class ApprovalBillServiceImpl extends ServiceImpl<ApprovalBillMapper, ApprovalBill> implements ApprovalBillService {

	@Autowired
	private ApprovalBillMapper approvalBillMapper;
	@Autowired
	private ApprovalBillDetailMapper approvalBillDetailMapper;
	@Autowired
	private ApprovedProjectMapper approvedProjectMapper;
	@Autowired
	private SubmitApprovedProjectService submitApprovedProjectService;

	@Value("${PORTAL_SYSCODE}")
	private String oaSysCode;
	@Value("${PORTAL_SECRET_KEY}")
	private String oaSecretKey;
	@Value("${oauthUrl}")
	String oauthUrl;
	@Value("${saveFlowUrl}")
	String saveFlowUrl;
	@Value("${endFlowUrl}")
	String endFlowUrl;
	@Value("${deleteFlowUrl}")
	String deleteFlowUrl;
	@Value("${flowOpinionsUrl}")
	String flowOpinionsUrl;
	@Value("${flowPathUrl}")
	String flowPathUrl;
	@Value("${previewUrl}")
	private String oaPreviewUrl;
	@Value("${view_approved_url}")
	private String reviewApprovalUrl;

	/**
	 * 提交审批
	 */
	@Transactional
	@Override
	public ApprovalBill submit(ApprovalSubmitBO param){
		ApprovalBill oaApproval = new ApprovalBill();

		//参数校验
		if( StringUtils.isBlank(param.getOaApprovalId()) ){
			if(StringUtils.isBlank(param.getAlias()) || StringUtils.isBlank(param.getFlowKey())
					|| StringUtils.isBlank(param.getSubject()) || StringUtils.isBlank(param.getProcessType())){
				throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
			}

			String billId = UUIDUtils.create();

			//审批单主键id
			oaApproval.setId(billId);
			//流程key
			oaApproval.setFlowKey(param.getFlowKey());
			//审批标题
			oaApproval.setSubject(param.getSubject());
			//审批类型
			oaApproval.setBusinessType(param.getProcessType());
			//项目id
			oaApproval.setProjectId(param.getProjectId());
			//发起人的岗位编码
			oaApproval.setPostCode(param.getPostCode());
			//发起人所属部门编码
			oaApproval.setOrgCode(param.getOrgCode());
			//审批要点说明
			oaApproval.setDescription(param.getDescription());
			//用户账户
			oaApproval.setAccount(param.getAlias());
			//用户名称
			oaApproval.setUsercn(param.getUsercn());
			//创建时间
			oaApproval.setCreatedTime(LocalDateTime.now());
			//更新时间
			oaApproval.setUpdateTime(LocalDateTime.now());
			//审批状态
			oaApproval.setState(ApprovedStateCodeEnum.DRAFT.getKey());
			oaApproval.setVars(param.getVars());
			//保存OA流程实例
			saveOaFlow(oaApproval);

			approvalBillMapper.insert(oaApproval);

			List<ApprovalBillDetail> detailList = param.getDetailList();
			if(CollectionUtils.isNotEmpty(detailList)){
				detailList.forEach(s->{
					s.setId(UUIDUtils.create());
					s.setBillId(billId);
				});
				approvalBillDetailMapper.insertList(detailList);
			}
		} else {
			//参数校验
			if(StringUtils.isBlank(param.getAlias()) || StringUtils.isBlank(param.getFlowKey())){
				throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
			}
			//获取审批单数据
			oaApproval =  approvalBillMapper.selectById(param.getOaApprovalId());
			if(null == oaApproval){
				throw new MsgException(CodeEnum.APPROVED_FLOW_NON_EXISTENT);
			}
			//用户账户
			oaApproval.setAccount(param.getAlias());
			oaApproval.setUsercn(param.getUsercn());
			//流程key
			oaApproval.setFlowKey(param.getFlowKey());
			//审批要点说明
			oaApproval.setDescription(param.getDescription());
			//更新时间
			oaApproval.setUpdateTime(LocalDateTime.now());
			oaApproval.setVars(param.getVars());
			//保存OA流程实例
			saveOaFlow(oaApproval);
			approvalBillMapper.updateById(oaApproval);
		}
		return oaApproval;
	}

	/**
	 * 	获取项目为提交的审批单
	 * @param projectId
	 * @param businessType
	 * @return
	 */
	@Override
	public ApprovalBill getNotSubmitApprovalBill(String projectId, String businessType) {
		List<String> stateList = Arrays.asList(ApprovedStateCodeEnum.DRAFT.getKey(), ApprovedStateCodeEnum.REJECT.getKey(), ApprovedStateCodeEnum.RECALL.getKey());
		return approvedProjectMapper.insertBillCheckV2(projectId, stateList, businessType);
	}


	/**
	 * 保存流程
	 * @param oaApproval
	 * @return
	 */
	private void saveOaFlow(ApprovalBill oaApproval){
		JSONObject jsonObjectSave = new JSONObject();
		jsonObjectSave.put("account",oaApproval.getAccount());
		jsonObjectSave.put("postCode",oaApproval.getPostCode());
		jsonObjectSave.put("orgCode",oaApproval.getPostCode());
		jsonObjectSave.put("businessKey",oaApproval.getId());
		jsonObjectSave.put("flowKey",oaApproval.getFlowKey());
		jsonObjectSave.put("sysCode",oaSysCode);
		jsonObjectSave.put("subject",oaApproval.getSubject());
		jsonObjectSave.put("backNormal",false);
		jsonObjectSave.put("agentAccount","");
		//发起推演组织编码（流程按此编码 组织为起始，推演审批流程）,设置为当前审批项目id
		jsonObjectSave.put("startOrgCode", oaApproval.getProjectId());
		jsonObjectSave.put("vars",oaApproval.getVars());
		jsonObjectSave.put("instanceId",oaApproval.getInstanceId());
		String requestSave = jsonObjectSave.toString();
		//获取认证token
		String authToken = this.getAuthToken();

		//保存流程实例
		String response = saveFlow(authToken, requestSave);

		JSONObject parseObject = JSONObject.parseObject(response);
		Boolean state = parseObject.getBoolean("state");
		String message = parseObject.getString("message");
		if (!state){
			throw new MsgException(CodeEnum.SAVE_FLOW_ERROR);
		}
		String instanceId = parseObject.getString("instId");
		oaApproval.setInstanceId(instanceId);

	}



	/**
	 * 获取审批预览Url
	 * @param approvalBill
	 * @return
	 */
	@Override
	public String getPreviewUrl(ApprovalBill approvalBill) {
		JSONObject instObject = new JSONObject();
		instObject.put("proInstId",approvalBill.getInstanceId());
		if(approvalBill.getState().equals(ApprovedStateCodeEnum.RECALL.getKey()) || approvalBill.getState().equals(ApprovedStateCodeEnum.REJECT.getKey())){
			instObject.put("taskId",approvalBill.getTaskId());
		}
		String previewUrl = "";
		Map<String,String> map = new HashMap<>();
		try {
			//AES加密
			String encode = Base64.getEncoder().encodeToString(instObject.toString().getBytes("utf-8"));
			previewUrl = oaPreviewUrl+encode;
		} catch (UnsupportedEncodingException e) {
			throw new MsgException(CodeEnum.AES_ENCRYPTION_ERROR);
		}

		return previewUrl;
	}


	/**
	 * 获取审批预览Url
	 * @param instanceId
	 * @param taskId
	 * @return
	 */
	@Override
	public String getReviewUrl(String instanceId, String taskId) {
		String revoewUrl = "";

		JSONObject instObject = new JSONObject();
		if(StringUtils.isNotEmpty(taskId)){
			instObject.put("proInstId",instanceId);
			instObject.put("taskId",taskId);
		}else {
			instObject.put("proInstId", instanceId);
		}

		try {
			String encode = Base64.getEncoder().encodeToString(instObject.toString().getBytes("utf-8"));
			revoewUrl = reviewApprovalUrl+encode;
		} catch (UnsupportedEncodingException e) {
			throw new MsgException(CodeEnum.AES_ENCRYPTION_ERROR);
		}
		return revoewUrl;
	}


	/**
	 * 获取认证token
	 * @return
	 */
	@Override
	public String getAuthToken(){
		JSONObject jsonObj = new JSONObject();
		jsonObj.put("sysCode",oaSysCode);
		jsonObj.put("secretKey",oaSecretKey);
		String authParams = jsonObj.toString();

		String authTokenStr = "";
		try {
			authTokenStr = RequestUtil.doPostBodyData(oauthUrl, authParams, null);
		}catch (Exception e){
			throw new MsgException(CodeEnum.GET_TOKEN_ERROR);
		}

		JSONObject authTokenJson = JSONObject.parseObject(authTokenStr);
		String authToken = authTokenJson.getString("token");
		return authToken;
	}

	/**
	 * 保存流程实例
	 */
	@Override
	public String saveFlow(String sessionToken, String flowParams) {
		String resultValue = null;
		try {
			resultValue = RequestUtil.doPostBodyData(saveFlowUrl, flowParams, sessionToken);
			log.info("saveFlowUrl:"+ saveFlowUrl);
			log.info("sessionToken:"+ sessionToken);
			log.info("flowParams:"+ flowParams);
			log.info("resultValue:" + resultValue);
		} catch (Exception e) {
			log.error("###### errorMsg: ", e);
		}
		return resultValue;
	}


	/**
	 * 废弃流程实例
	 */
	@Override
	public String endFlow(String sessionToken, String endFlowParams) {
		String resultValue = null;
		try {
			resultValue = RequestUtil.doPostBodyData(endFlowUrl, endFlowParams, sessionToken);
			log.info("endFlowUrl:"+ endFlowUrl);
			log.info("sessionToken:"+ sessionToken);
			log.info("endFlowParams:"+ endFlowParams);
			log.info("resultValue:" + resultValue);
		} catch (Exception e) {
			log.error("###### errorMsg: ", e);
		}
		return resultValue;
	}
	/**
	 * 删除流程实例
	 */
	@Override
	public String deleteFlow(String sessionToken, String deleteFlowParams) {
		String resultValue = null;
		try {
			resultValue = RequestUtil.doPostBodyData(deleteFlowUrl, deleteFlowParams, sessionToken);
			log.info("deleteFlowUrl:"+ deleteFlowUrl);
			log.info("sessionToken:"+ sessionToken);
			log.info("deleteFlowParams:"+ deleteFlowParams);
			log.info("resultValue:" + resultValue);
		} catch (Exception e) {
			log.error("###### errorMsg: ", e);
		}
		return resultValue;
	}
	/**
	 * 查询流程实例的审批记录
	 */
	@Override
	public String selectFlowOpt(String sessionToken, String flowOptParams) {
		String resultValue = null;
		try {
			resultValue = RequestUtil.doPostBodyData(flowOpinionsUrl, flowOptParams, sessionToken);
			log.info("flowOpinionsUrl:"+ flowOpinionsUrl);
			log.info("sessionToken:"+ sessionToken);
			log.info("flowOptParams:"+ flowOptParams);
			log.info("resultValue:" + resultValue);
		} catch (Exception e) {
			log.error("###### errorMsg: ", e);
		}
		return resultValue;
	}
	/**
	 * 查询流程实例的审批路径
	 */
	@Override
	public String selectFlowPath(String sessionToken, String flowPathParams) {
		String resultValue = null;
		try {
			resultValue = RequestUtil.doPostBodyData(flowPathUrl, flowPathParams, sessionToken);
			log.info("flowPathUrl:"+ flowPathUrl);
			log.info("sessionToken:"+ sessionToken);
			log.info("flowPathParams:"+ flowPathParams);
			log.info("resultValue:" + resultValue);
		} catch (Exception e) {
			log.error("###### errorMsg: ", e);
		}
		return resultValue;
	}

	/**
	 * 根据OA消息,更新审批单状态
	 * @param approvalId 审批单id
	 * @param taskId 任务id
	 * @param status 审批状态
	 */
	@Override
	public void updateByOA(String approvalId, String taskId, String status) {
		List<String> approvalState1List = Arrays.asList(ApprovedStateCodeEnum.DELETE.getKey(), ApprovedStateCodeEnum.APPROVAL.getKey(), ApprovedStateCodeEnum.APPROVAL_SUCCESS.getKey());
		List<String> approvalState2List = Arrays.asList(ApprovedStateCodeEnum.REJECT.getKey(), ApprovedStateCodeEnum.RECALL.getKey());
		if(approvalState1List.contains(status)){
			submitApprovedProjectService.updateApprovalState(approvalId, status,null, null, LocalDateTime.now());
		}else if(approvalState2List.contains(status)){
			submitApprovedProjectService.updateApprovalState(approvalId, status,null, taskId, LocalDateTime.now());
		}
		SysLogUtils.addSysLog(LogEventEnum.MQ,"OA消息接收","更新单据状态","单据ID：" + approvalId + "；状态更新为：" + status );
	}


}
